package com.panopset.compat;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * Resource IO methods extracted from UtilIO.  Droid compatible.
 * @author Karl Dinwiddie
 *
 */
public final class RezIO {

    /**
     *
     * @param resourcePath
     *            Resource path.
     * @param clazz
     *            Class in same jar as resource.
     * @return All lines from resourcePath except empty or blank.
     * @throws IOException
     *             IOException.
     */
    public static List<String> loadLinesFromResourceTrim(

    final String resourcePath,
    final Class<?> clazz) throws IOException {

        List<String> rtn = new ArrayList<String>();
        for (String s : loadLinesFromResource(resourcePath, clazz)) {
            if (Strings.isPopulated(s.trim())) {
                rtn.add(s);
            }
        }
        return rtn;
    }

    /**
     * Load lines from resource.
     *
     * @param resourcePath
     *            Resource path to a text file.
     * @param clazz Class in same jar as resource.
     * @return List of lines.
     * @throws IOException
     *             IOException.
     */
    public static List<String> loadLinesFromResource(

    final String resourcePath, final Class<?> clazz) throws IOException {
        List<String> rtn = new ArrayList<String>();
        try {
            BufferedReader br = new BufferedReader(new StringReader(
                    loadTextFromResource(resourcePath, clazz)));
            String s = br.readLine();
            while (s != null) {
                rtn.add(s);
                s = br.readLine();
            }
        } catch (IOException e) {
            throw new IOException(resourcePath);
        }
        return rtn;
    }


    /**
     * @param resourcePath
     *            resource path.
     * @param clazz Class in same jar as resource.
     * @return String from resourcePath.
     * @throws IOException
     *             IOException.
     */
    public static String loadTextFromResource(final String resourcePath,
            final Class<?> clazz)
            throws IOException {
        StringWriter sw = new StringWriter();
        BufferedInputStream bis = null;
        try {
            bis = getResourceStream(resourcePath, clazz);
            int i;
            i = bis.read();
            while (i != -1) {
                sw.append((char) i);
                i = bis.read();
            }
            bis.close();
        } catch (IOException e) {
            Util.log(e);
        } finally {
            if (bis != null) {
                bis.close();
            }
        }
        return sw.toString();
    }

    /**
     * Get resource stream.
     *
     * @param resourcePath
     *            Resource path.
     * @param clazz
     *            Class in same jar as resource.
     * @return Buffered input stream.
     */
    public static BufferedInputStream getResourceStream(
            final String resourcePath, final Class<?> clazz) {
        return new BufferedInputStream(
                clazz.getResourceAsStream(resourcePath));
    }

    /**
     * Load lines from resource.
     *
     * @param resourcePath
     *            Resource path to a text file.
     * @return List of lines.
     * @throws IOException
     *             IOException.
     */
    public static List<String> loadLinesFromResource(

    final String resourcePath) throws IOException {
        List<String> rtn = new ArrayList<String>();
        try {
            BufferedReader br = new BufferedReader(new StringReader(
                    loadTextFromResource(resourcePath)));
            String s = br.readLine();
            while (s != null) {
                rtn.add(s);
                s = br.readLine();
            }
        } catch (IOException e) {
            throw new IOException(resourcePath);
        }
        return rtn;
    }


    /**
     * @param resourcePath
     *            resource path.
     * @return String from resourcePath.
     */
    public static String loadTextFromResource(final String resourcePath) {
        StringWriter sw = new StringWriter();
        BufferedInputStream bis = null;
        try {
            bis = getResourceStream(resourcePath);
            int i;
            i = bis.read();
            while (i != -1) {
                sw.append((char) i);
                i = bis.read();
            }
            bis.close();
        } catch (IOException e) {
            Util.log(e);
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return sw.toString();
    }

    /**
     * Get resource stream.
     *
     * @param resourcePath
     *            Resource path.
     * @return Buffered input stream.
     */
    public static BufferedInputStream getResourceStream(
            final String resourcePath) {
        return new BufferedInputStream(
                RezIO.class.getResourceAsStream(resourcePath));
    }

    /**
     * Load lines from resource.
     *
     * @param clazz
     *            Class who's package contains the resource.
     * @param name
     *            Text file name.
     * @return List of lines.
     * @throws IOException
     *             IOException.
     */
    public static List<String> loadLinesFromResource(

    final Class<?> clazz, final String name) throws IOException {
        return loadLinesFromResource(getResourcePath(clazz, name));
    }

    /**
     *
     * @param resourcePath
     *            Resource path.
     * @return All lines from resourcePath except empty or blank.
     * @throws IOException
     *             IOException.
     */
    public static List<String> loadLinesFromResourceTrim(

    final String resourcePath) throws IOException {

        List<String> rtn = new ArrayList<String>();
        for (String s : loadLinesFromResource(resourcePath)) {
            if (Strings.isPopulated(s.trim())) {
                rtn.add(s);
            }
        }
        return rtn;
    }

    /**
     * Get resource path. Class resource resides in same package as this class.
     *
     * @param clazz
     *            Class resource resides in same package as this class.
     * @param name
     *            Name of resource.
     * @return Path name. If the clazz is com.package, and the name is rsrc,
     *         returns <b>/com/package/rsrc</b>.
     */
    public static String getResourcePath(

    final Class<?> clazz, final String name) {
        final StringWriter sw = new StringWriter();
        sw.append("/");
        sw.append(getPackagePath(clazz, name));
        return sw.toString();
    }

    /**
     * Get package path. Class resource resides in same package as this class.
     *
     * @param clazz
     *            Class resource resides in same package as this class.
     * @param name
     *            Name of resource.
     * @return Path name. If the clazz is com.package, and the name is rsrc,
     *         returns <b>com/package/rsrc</b>.
     */
    public static String getPackagePath(

    final Class<?> clazz, final String name) {
        final StringWriter sw = new StringWriter();
        sw.append(clazz.getPackage().getName().replace(".", "/"));
        sw.append("/");
        sw.append(name);
        return sw.toString();
    }

    /**
     * Load lines from resource.
     *
     * @param clazz
     *            Class resource resides in same package as this class.
     * @param name
     *            Name of resource.
     * @return Lines from resource file.
     * @throws IOException
     *             IOException.
     */
    public static String[] loadLineArrayFromResource(final Class<?> clazz,
            final String name) throws IOException {
        String[] rtn = null;
        final String path = getResourcePath(clazz, name);
        Object[] oa = loadLinesFromResource(path).toArray();
        rtn = new String[oa.length];
        int i = 0;
        for (Object o : oa) {
            rtn[i++] = o.toString();
        }
        return new String[0];
    }

    /**
     * Copy text resource to file.
     *
     * @param resourcePath
     *            Resource path.
     * @param fileName
     *            File name.
     * @throws IOException
     *             IOException.
     */
    public static void copyTextResourceToFile(final String resourcePath,
            final String fileName) throws IOException {
        File f = new File(fileName);
        if (!f.getParentFile().exists() && !f.getParentFile().mkdirs()) {
            Logger.log("from resource:" + resourcePath);
            Logger.log("target file:" + getCanonicalPath(f));
            Logger.log(getCanonicalPath(f.getParentFile()));
            throw new FileNotFoundException();
        }
        FileWriter fw = new FileWriter(f);
        BufferedWriter bw = new BufferedWriter(fw);
        StringReader sr = new StringReader(loadTextFromResource(resourcePath));
        BufferedReader br = new BufferedReader(sr);
        String s = br.readLine();
        while (s != null) {
            bw.write(s);
            bw.write(Strings.getEol());
            s = br.readLine();
        }
        bw.flush();
        bw.close();
        br.close();
    }
    /**
     * Copy text resource to file.
     *
     * @param resourcePath
     *            Resource path.
     * @param fileName
     *            File name.
     * @param clazz
     *            Class in same jar as resource.
     * @throws IOException
     *             IOException.
     */
    public static void copyTextResourceToFile(final String resourcePath,
            final String fileName,
            final Class<?> clazz) throws IOException {
        File f = new File(fileName);
        if (!f.getParentFile().exists() && !f.getParentFile().mkdirs()) {
            Logger.log("from resource:" + resourcePath);
            Logger.log("target file:" + getCanonicalPath(f));
            Logger.log(getCanonicalPath(f.getParentFile()));
            throw new FileNotFoundException();
        }
        FileWriter fw = new FileWriter(f);
        BufferedWriter bw = new BufferedWriter(fw);
        StringReader sr = new StringReader(
               loadTextFromResource(resourcePath, clazz));
        BufferedReader br = new BufferedReader(sr);
        String s = br.readLine();
        while (s != null) {
            bw.write(s);
            bw.write(Strings.getEol());
            s = br.readLine();
        }
        bw.flush();
        bw.close();
        br.close();
    }

    /**
     * Copy text resource to file.
     *
     * @param resourcePath
     *            Resource path.
     * @param fileName
     *            File name.
     * @param classNm
     *            Name of class in same jar as resource.
     * @throws Exception
     *             Exception.
     */
    public static void copyTextResourceToFile(final String resourcePath,
            final String fileName,
            final String classNm) throws Exception {
         copyTextResourceToFile(resourcePath, fileName, Class.forName(classNm));
    }

    /**
     * Load text from a package resource.
     *
     * @param clazz
     *            Class in the same package as the resource.
     * @param name
     *            Text file name.
     * @return Contents of text file.
     * @throws IOException
     *             Exception.
     */
    public static String loadTextFromResource(final Class<?> clazz,
            final String name) throws IOException {
        StringWriter sw = new StringWriter();
        sw.append(pkg2resourcePath(clazz));
        sw.append(name);
        return loadTextFromResource(sw.toString());
    }

    /**
     * @param clazz
     *            Class.
     * @return Converts . to /.
     */
    public static String pkg2resourcePath(final Class<?> clazz) {
        StringWriter sw = new StringWriter();
        sw.append("/");
        sw.append(clazz.getPackage().getName().replace(".", "/"));
        sw.append("/");
        return sw.toString();
    }

    /**
     * Load lines from a text resource file.
     *
     * @param clazz
     *            Class in the same package as resource to load.
     * @param name
     *            File name.
     * @return List<String> Lines.
     * @throws IOException
     *             IOException.
     */
    public static List<String> loadLinesFromTextResource(final Class<?> clazz,
            final String name) throws IOException {
        return loadLinesFromResource(getResourcePath(clazz, name));
    }

    /**
     * Wrapper for java.io.File.getCanonicalPath method, to handle IOException.
     * If an IOException is caught, the exception is logged by the log function,
     * and the results of the Exception.getMessage function are returned.
     *
     * @param f
     *            File to get canonical path of.
     * @return result of java.io.File.getCanonicalPath
     */
    public static String getCanonicalPath(final File f) {
        try {
            if (f == null) {
                return "";
            }
            return f.getCanonicalPath();
        } catch (IOException e) {
            Util.log(e);
            return e.getMessage();
        }
    }

    /**
     * Prevent instantiation.
     */
    private RezIO() {
    }
}
